/*
 * transmission.c
 *
 * Created: 12/17/2012 12:17:26 PM
 *  Author: duerk@msoe.edu <Kevin Duer>
 *			zimmermane@msoe.edu <Evan Zimmerman>
 *			woottons@msoe.edu <Scott Wootton>
 *			
 * Purpose: to transmit data in the form of ASCII characters on the channel
 */ 

#include <stdbool.h>		//for boolean
#include "transmission.h"			//header file for this class
#include<avr/io.h>					//i/o register definitions
#include <stdio.h>
#include<avr/interrupt.h>			//interrupt definitions
#include<stdint.h>					//for uint types
#include "channelmonitor.h"
#include <util/delay.h>
#include <stdlib.h>

volatile uint8_t count = 16;

#define BUFFER_LENGTH 40

volatile uint16_t networkBuffer[BUFFER_LENGTH] = {0};
volatile uint8_t bufferCount = 0;
volatile uint8_t bufferLength = 0;


void addNetworkChar(volatile char* c)
{
	while(transmitting); //Wait until the transmission is complete
	transmitting = true;
	uint8_t i;
	for(i = 0; (i < BUFFER_LENGTH) && (c[i] != '\0') && (c[i] != '\n') && (c[i] != '\r'); i++)
	{
		char cur = c[i];
		uint16_t temp = encodeChar(cur);
		networkBuffer[i] = temp;
	}
	count = 0;
	bufferLength = i;
	networkBuffer[i] = 0;
	bufferCount = 0;
	while((!idle) || (busy) || (collision));
	TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
}

void handleCollision()
{
	bufferCount = 0;
	count = 0;
	TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
	PORTD |= (1<<OC2); //Output a solid 1
}

void handleIdle()
{
	if(transmitting){
		bufferCount = 0;
		count = 0;
		_delay_ms((rand()%128)+1);
		if((idle) && (!busy) && (!collision))
		{
			TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
		} else {
			handleIdle();
		}
	}	
}

/* initTX
 * 
 * Purpose: To initialize the the transmit functionality
 * Params: none
 * Returns: none
 */
void initTx(){
	DDRD |= (1<<PD7); //Set PD7 to be an output
	PORTD |= (1<<PD7);
	TCCR2 = (1<<WGM21)|(0<<WGM20); //CTC Mode without a prescaler
	//TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
	//TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on
	OCR2 = BIT_OVERFLOW;
	TIMSK |= (1<<OCIE2); //Enable Timer2 Output Compare
	TCNT2 = 0; //Reset the timer count
	count = 0; //Set the count to the max
	sei();
}

uint16_t encodeChar(char c)
{
	uint16_t ret = 0x0000;
	char toSend = c|(1<<7);
	volatile int i;
	for(i = 0; i < 8; ++i)
	{
		uint16_t encode;
		if(((toSend>>i)&(0x01)) == 1)
		{
			//1 transmitted
			encode = 0x0002;
		} else {
			//0 Transmitted
			encode = 0x0001;
		}
		//Shift the data by 1 and put the new bit at the end
		ret = (ret<<2) | encode;
	}
	return ret;
}

void startTransmission()
{
	TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
}

/* TIMER0_COMP_vect
 * 
 * Purpose: Used to transmit the data
 * Params: none
 * Returns: none
 */
ISR(TIMER2_COMP_vect){
	//Reset the timer
	TCNT2 = 0;
	if(bufferCount < bufferLength)
	{
		//Send stuff
		uint16_t data = networkBuffer[bufferCount];
		PORTD = (((data>>count)&(0x0001))<<OC2); //Output the current bit and move it
		count++; //bit sent
		if(count >= 16)
		{
			count = 0;
			bufferCount++;
		}
	} else {
		//no more
		TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
		PORTD |= (1<<OC2); //Output a solid 1
		//Reached the end so transmit a solid 1 and turn the timer off
		TCNT2 = 0; //Reset the count
		transmitting = false;
	}
}
